package com.cqfae.deploycentral.app.services.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cqfae.deploycentral.api.utils.IdGenerator;
import com.cqfae.deploycentral.app.base.BaseConstantCode;
import com.cqfae.deploycentral.app.base.BaseConstants;
import com.cqfae.deploycentral.app.config.JenkinsInfo;
import com.cqfae.deploycentral.app.dao.entity.*;
import com.cqfae.deploycentral.app.dao.mapper.*;
import com.cqfae.deploycentral.app.services.ConstantsCodeService;
import com.cqfae.deploycentral.app.services.InspectService;
import com.cqfae.deploycentral.app.utils.ConvertUtil;
import com.cqfae.deploycentral.app.utils.GsonUtils;
import com.cqfae.deploycentral.app.web.request.AppInfoRequest;
import com.cqfae.deploycentral.app.web.request.ConstantsCodeRequest;
import com.cqfae.deploycentral.app.web.request.InspectRequest;
import com.cqfae.deploycentral.app.web.response.IPage;
import com.cqfae.deploycentral.app.web.vo.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import tk.mybatis.mapper.entity.Example;

import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by JIANGLU009 on 2017/12/21.
 */
@Service
@Transactional
public class InspectServiceImpl implements InspectService {

    private static Logger logger = LoggerFactory.getLogger(InspectServiceImpl.class);

    // 获取ID
    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private InspectStatisticsMapper inspectStatisticsMapper;

    @Autowired
    private InspectHistoryMapper inspectHistoryMapper;

    @Autowired
    private InspectHistoryItemsMapper inspectHistoryItemsMapper;

    @Autowired
    private AppInfoMapper appInfoMapper;

    @Autowired
    private InspectAreaAppMapper inspectAreaAppMapper;

    @Autowired
    private ConstantsCodeService constantsCodeService;

    @Autowired
    private JenkinsInfo jenkinsInfo;

    private String jenkinsQueryMsg = "查询请求发送成功";

    private String sqlCityCode = "cityCode";

    private String valueStr = "value";

    private String statusStr = "status";

    private String userJenkins = "Jenkins";

    private String ymFormatStr = "yyyyMM";

    private String batchNumStr = "batchNum";

    /**
     * 查询城市
     *
     * @return
     */
    @Override
    public List<SelectedVo> getCity() {
        ConstantsCodeRequest request = new ConstantsCodeRequest();
        // 巡查城市parentCode=39
        request.setParentCode("31");
        return constantsCodeService.getInfoByParentCode(request);
    }

    /**
     * 查询巡查统计，如果某天没有数据则填充空数据
     *
     * @param inspectStatisticsVo
     * @return
     */
    @Override
    public List<InspectStatisticsVo> getStatistics(InspectStatisticsVo inspectStatisticsVo) {
        if (StringUtils.isBlank(inspectStatisticsVo.getDateYm())) {
            // 取得今天的日期
            String today = new SimpleDateFormat(ymFormatStr).format(new Date());
            inspectStatisticsVo.setDateYm(today);
        } else {
            // 去掉横杠
            inspectStatisticsVo.setDateYm(inspectStatisticsVo.getDateYm().replace("-", ""));
        }
        // 查询数据库巡查数据
        Example example = new Example(InspectStatistics.class);
        example.orderBy("dateD").asc();
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotBlank(inspectStatisticsVo.getCityCode())) {
            criteria.andEqualTo(sqlCityCode, inspectStatisticsVo.getCityCode());
        }
        criteria.andEqualTo("dateYm", inspectStatisticsVo.getDateYm());
        List<InspectStatistics> inspectStatisticsList = inspectStatisticsMapper.selectByExample(example);
        // 保存巡查展示数据
        List<InspectStatisticsVo> inspectStatisticsVoList = new ArrayList<>();

        Map<String, InspectStatistics> map = new HashMap<>();
        // 以day-bean保存巡查数据
        for (InspectStatistics inspectStatistics : inspectStatisticsList) {
            InspectStatistics inspectStatisticsNew;
            String dataD = String.valueOf(Integer.parseInt(inspectStatistics.getDateD()));
            if (map.get(dataD) != null) {
                inspectStatisticsNew = map.get(dataD);
                inspectStatisticsNew.setNormalCount(inspectStatisticsNew.getNormalCount() + inspectStatistics.getNormalCount());
                inspectStatisticsNew.setExceptionCount(inspectStatisticsNew.getExceptionCount() + inspectStatistics.getExceptionCount());
            } else {
                inspectStatisticsNew = new InspectStatistics();
                inspectStatisticsNew.setNormalCount(inspectStatistics.getNormalCount());
                inspectStatisticsNew.setExceptionCount(inspectStatistics.getExceptionCount());
            }
            map.put(dataD, inspectStatisticsNew);
        }
        // 城市code和日期
        String cityCode = inspectStatisticsVo.getCityCode();
        String cityName = inspectStatisticsVo.getCityName();
        String dateYm = inspectStatisticsVo.getDateYm();
        // 拿取最后一天的数据
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(new SimpleDateFormat(ymFormatStr).parse(inspectStatisticsVo.getDateYm()));
        } catch (ParseException e) {
            logger.error("日期获取错误：{}", e);
        }
        calendar.add(Calendar.MARCH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 0);
        int lastDay = Integer.parseInt(new SimpleDateFormat("dd").format(calendar.getTime()));
        // 整合数据
        for (int i = 1; i <= lastDay; i++) {
            InspectStatisticsVo inspectStatisticsVo1 = new InspectStatisticsVo();
            inspectStatisticsVo1.setCityCode(cityCode);
            inspectStatisticsVo1.setCityName(cityName);
            inspectStatisticsVo1.setDateYm(dateYm);
            inspectStatisticsVo1.setDateD(String.valueOf(i));
            inspectStatisticsVo1.setNormalStatus(BaseConstantCode.INSPECT_STATUS_NORMAL);
            inspectStatisticsVo1.setExceptionStatus(BaseConstantCode.INSPECT_STATUS_EXCEPTION);
            if (map.get(String.valueOf(i)) != null) {
                InspectStatistics inspectStatistics = map.get(String.valueOf(i));
                inspectStatisticsVo1.setExceptionCount(inspectStatistics.getExceptionCount());
                inspectStatisticsVo1.setNormalCount(inspectStatistics.getNormalCount());
            } else {
                // 如果某天没有数据则填充空数据
                inspectStatisticsVo1.setExceptionCount(0L);
                inspectStatisticsVo1.setNormalCount(0L);
            }
            inspectStatisticsVoList.add(inspectStatisticsVo1);
        }

        return inspectStatisticsVoList;
    }

    /**
     * 查询巡查历史表
     *
     * @param inspectRequest
     * @return
     */
    @Override
    public IPage<InspectHistoryVo> getHistory(InspectRequest inspectRequest) {
        // 创建翻页对象
        Page<InspectHistory> page = PageHelper.startPage(inspectRequest.getPageNum(), inspectRequest.getPageSize());
        Example example = new Example(InspectHistory.class);
        Example.Criteria criteria = example.createCriteria();
        example.orderBy("createTime").desc();
        if (inspectRequest.getBeginDate() > 0 || inspectRequest.getEndDate() > 0) {
            criteria.andBetween("date", inspectRequest.getBeginDate(), inspectRequest.getEndDate());
        }
        if (inspectRequest.getType() != null) {
            criteria.andEqualTo("type", inspectRequest.getType());
        }
        if (StringUtils.isNotBlank(inspectRequest.getCityCode())) {
            criteria.andEqualTo(sqlCityCode, inspectRequest.getCityCode());
        }
        if (StringUtils.isNotBlank(inspectRequest.getAppName())) {
            criteria.andLike("appName", "%" + inspectRequest.getAppName() + "%");
        }
        if (inspectRequest.getStatus() != null) {
            criteria.andEqualTo(statusStr, inspectRequest.getStatus());
        }
        if (StringUtils.isNotBlank(inspectRequest.getTime())) {
            criteria.andEqualTo("date", inspectRequest.getTime().replace("-", ""));
        }
        inspectHistoryMapper.selectByExample(example);
        IPage<InspectHistoryVo> iPage = ConvertUtil.pageToIpage(page, new IPage<InspectHistoryVo>());
        List<InspectHistoryVo> inspectHistoryVoList = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<InspectHistoryVo>>() {
        }.getType());

        // 将code转换为name
        for (InspectHistoryVo inspectHistoryVo1 : inspectHistoryVoList) {
            inspectHistoryVo1.setTypeStr(BaseConstants.getConstantsCodeMap().get(inspectHistoryVo1.getType()));
            inspectHistoryVo1.setStatusStr(BaseConstants.getConstantsCodeMap().get(inspectHistoryVo1.getStatus()));
            // 用于查询详情
            inspectHistoryVo1.setHistoryId(inspectHistoryVo1.getId());
        }
        iPage.setResult(inspectHistoryVoList);
        return iPage;
    }

    /**
     * 查询巡查历史详情表
     *
     * @param inspectRequest
     * @return
     */
    @Override
    public IPage<InspectHistoryItemsVo> getHistoryItem(InspectRequest inspectRequest) {
        // 创建翻页对象
        Page<InspectHistoryItems> page = PageHelper.startPage(inspectRequest.getPageNum(), inspectRequest.getPageSize());
        List<InspectHistoryItemsVo> inspectHistoryItemsVoList = new ArrayList<>();
        Example example = new Example(InspectHistoryItems.class);
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();
        if (inspectRequest.getItemStatus() != null) {
            criteria.andEqualTo(statusStr, inspectRequest.getItemStatus());
        }
        criteria.andEqualTo("historyId", inspectRequest.getHistoryId());
        inspectHistoryItemsMapper.selectByExample(example);
        IPage<InspectHistoryItemsVo> iPage = ConvertUtil.pageToIpage(page, new IPage<InspectHistoryItemsVo>());
        List<InspectHistoryItems> inspectHistoryItemsList = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<InspectHistoryItems>>() {
        }.getType());
        for (InspectHistoryItems inspectHistoryItems : inspectHistoryItemsList) {
            InspectHistoryItemsVo inspectHistoryItemsVo1 = new InspectHistoryItemsVo();
            inspectHistoryItemsVo1.setHistoryId(inspectHistoryItems.getHistoryId());
            inspectHistoryItemsVo1.setName(inspectHistoryItems.getName());
            inspectHistoryItemsVo1.setItemStatus(inspectHistoryItems.getStatus());
            inspectHistoryItemsVo1.setItemStatusStr(BaseConstants.getConstantsCodeMap().get(inspectHistoryItems.getStatus()));
            inspectHistoryItemsVo1.setRemark(inspectHistoryItems.getRemark());
            String info = BaseConstants.getConstantsCodeMap().get(BaseConstantCode.INSPECT_INSTRUCTION_STRING);
            info = MessageFormat.format(info, inspectHistoryItems.getInfoKey(),
                    inspectHistoryItems.getInfoValue(),
                    BaseConstants.getConstantsCodeMap().get(inspectHistoryItems.getInfoStatus()),
                    inspectHistoryItems.getInfoDescribe());
            inspectHistoryItemsVo1.setInfo(info);
            inspectHistoryItemsVoList.add(inspectHistoryItemsVo1);
        }
        iPage.setResult(inspectHistoryItemsVoList);
        return iPage;
    }


    /**
     * 健康巡查
     *
     * @param inspectHistoryVo
     * @return
     */
    @Override
    public String healthCheck(InspectHistoryVo inspectHistoryVo) {
        // 根据项目名称获得项目数据
        InspectAreaApp inspectAreaApp = new InspectAreaApp();
        String appName = inspectHistoryVo.getAppName();
        inspectAreaApp.setAppName(appName);
        // 兼容参数有无城市code的情况
        if (StringUtils.isNotBlank(inspectHistoryVo.getCityCode())) {
            inspectAreaApp.setCityCode(inspectHistoryVo.getCityCode());
        }
        List<InspectAreaApp> inspectAreaAppList = inspectAreaAppMapper.select(inspectAreaApp);
        // 验证是否做了巡查配置
        Assert.isTrue(!inspectAreaAppList.isEmpty(), appName + "未配置巡查项目");
        // 调用Jenkins相关巡检
        logger.info("healthCheck:single, appName:{}", appName);
        jenkinsHealthJob(inspectAreaAppList, BaseConstantCode.INSPECT_STATUS_HAND);
        return jenkinsQueryMsg;

    }

    /**
     * 定时任务，获取Jenkins巡检数据
     */
    @Override
    public int execJenkinsInspect() {
        List<InspectAreaApp> inspectAreaAppList = inspectAreaAppMapper.selectAll();
        logger.info("healthCheck:all, checkTime:{}", new Date());
        if (!inspectAreaAppList.isEmpty()) {
            jenkinsHealthJob(inspectAreaAppList, BaseConstantCode.INSPECT_STATUS_AUTO);
        }
        return BaseConstantCode.JENKINS_DEPLOY_SUCCESS;
    }

    /**
     * 健康巡查jenkins回调
     *
     * @param inspectParams
     */
    @Override
    public int healthCheckCallBack(String inspectParams) {
        JSONObject jsonObject = JSONObject.parseObject(inspectParams);
        // 获取执行jobId
        String batchNum = String.valueOf(jsonObject.get("hcjobid"));
        // 获取城市编码
        String cityCode = String.valueOf(jsonObject.get("hccity"));
        // 获取巡查结果
        if (jsonObject.get("hcresults") == null) {
            return 0;
        }
        JSONArray resultsJsonArray = (JSONArray) JSONArray.parse(String.valueOf(jsonObject.get("hcresults")));
        // 正常系统数量
        Long normalCount = 0L;
        // 异常系统数量
        Long exceptionCount = 0L;
        // 是否为自动巡查，自动巡查修改统计，其他则不
        String isAuto = BaseConstantCode.INSPECT_STATUS_AUTO;
        // 解析数据
        for (int json = 0; json < resultsJsonArray.size(); json++) {
            JSONObject jsonHCResult = (JSONObject) resultsJsonArray.get(json);
            JSONObject jsonResult = (JSONObject) jsonHCResult.get("hcresult");
            // 默认设置系统为正常状态
            String statusApp = BaseConstantCode.INSPECT_STATUS_NORMAL;
            // 获取系统名称
            String appName = String.valueOf(jsonResult.get("app"));
            // 系统布置url
            String url = String.valueOf(jsonResult.get("hcurl"));
            // 获取系统url应巡查结果
            String inspectDataStr = String.valueOf(jsonResult.get("result"));
            // 解析巡查结果
            JSONObject inspectData = JSONObject.parseObject(inspectDataStr);
            // 项目描述
            String appDesc = (String) inspectData.get("appDesc");
            // 查询巡检历史
            InspectHistory inspectHistory = new InspectHistory();
            inspectHistory.setBatchNum(Long.parseLong(batchNum));
            inspectHistory.setDeployUrl(url);
            Example exampleAppInfo = new Example(AppInfo.class);
            exampleAppInfo.createCriteria().andLike("buildUrl", "/" + appName + "%");
            List<AppInfo> appInfoList = appInfoMapper.selectByExample(exampleAppInfo);
            if (appInfoList.isEmpty() || StringUtils.isBlank(inspectDataStr)) {
                continue;
            }
            String appRealName = appInfoList.get(0).getAppName();
            inspectHistory.setAppName(appRealName);
            inspectHistory.setCityCode(cityCode);
            inspectHistory = inspectHistoryMapper.selectOne(inspectHistory);
            // 查询数据为空时，定义为数据异常
            if (inspectHistory != null && inspectHistory.getId() != null) {
                if (BaseConstantCode.INSPECT_STATUS_HAND.equalsIgnoreCase(inspectHistory.getIsAuto())) {
                    isAuto = BaseConstantCode.INSPECT_STATUS_HAND;
                }
                // 默认设置巡查项目为正常状态
                String status = BaseConstantCode.INSPECT_STATUS_NORMAL;
                // 解析巡查结果详情
                JSONArray jsonArray = (JSONArray) inspectData.get("items");
                // 插入巡检历史详情前，先删除后添加
                Example example = new Example(InspectHistoryItems.class);
                example.createCriteria().andEqualTo("historyId", inspectHistory.getId());
                inspectHistoryItemsMapper.deleteByExample(example);
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObjectItem = (JSONObject) jsonArray.get(i);
                    int statusItem = (int) jsonObjectItem.get(statusStr);
                    String statusItemStr = BaseConstantCode.INSPECT_STATUS_NORMAL;
                    // 将0，-1转换为发布中心编码
                    if (statusItem == -1) {
                        status = BaseConstantCode.INSPECT_STATUS_EXCEPTION;
                        statusItemStr = BaseConstantCode.INSPECT_STATUS_EXCEPTION;
                    }
                    String name = (String) jsonObjectItem.get("name");
                    String remark = (String) jsonObjectItem.get("remark");
                    JSONArray jsonArrayInfos = (JSONArray) jsonObjectItem.get("infos");
                    if (jsonArrayInfos != null) {
                        for (int k = 0; k < jsonArrayInfos.size(); k++) {
                            JSONObject jsonObjectInfo = (JSONObject) jsonArrayInfos.get(k);
                            String key = (String) jsonObjectInfo.get("key");
                            int statusItemInfo = (int) jsonObjectInfo.get(statusStr);
                            String statusItemInfoStr = BaseConstantCode.INSPECT_STATUS_NORMAL;
                            // 将0，-1转换为发布中心编码
                            if (statusItemInfo == -1) {
                                statusApp = BaseConstantCode.INSPECT_STATUS_EXCEPTION;
                                statusItemInfoStr = BaseConstantCode.INSPECT_STATUS_EXCEPTION;
                            }
                            String value = (String) jsonObjectInfo.get(valueStr);
                            String describe = (String) jsonObjectInfo.get("describe");
                            InspectHistoryItems inspectHistoryItems = new InspectHistoryItems();
                            inspectHistoryItems.setId(idGenerator.nextId());
                            inspectHistoryItems.setHistoryId(inspectHistory.getId());
                            inspectHistoryItems.setName(name);
                            inspectHistoryItems.setRemark(remark);
                            inspectHistoryItems.setStatus(statusItemStr);
                            inspectHistoryItems.setInfoKey(key);
                            inspectHistoryItems.setInfoValue(value);
                            inspectHistoryItems.setInfoStatus(statusItemInfoStr);
                            inspectHistoryItems.setInfoDescribe(describe);
                            inspectHistoryItems.setCreateBy(userJenkins);
                            inspectHistoryItems.setCreateTime(new Date());
                            inspectHistoryItemsMapper.insert(inspectHistoryItems);
                        }
                    }
                }

                // 更新巡检历史
                inspectHistory.setAppDesc(appDesc);
                inspectHistory.setStatus(status);
                inspectHistory.setUpdateBy(userJenkins);
                inspectHistory.setUpdateTime(new Date());
                inspectHistoryMapper.updateByPrimaryKey(inspectHistory);
            } else {
                isAuto = BaseConstantCode.INSPECT_STATUS_HAND;
                // 数据异常
                logger.error("city: {} appName: {} ,url: {}, batchNum: {} data Exception", cityCode, batchNum, url, batchNum);
                statusApp = BaseConstantCode.INSPECT_STATUS_EXCEPTION;
            }

            if (BaseConstantCode.INSPECT_STATUS_NORMAL.equalsIgnoreCase(statusApp)) {
                normalCount++;
            } else {
                exceptionCount++;
            }
        }
        // 查询巡查app数量
        return statisticsInsertOrUpdate(cityCode, normalCount, exceptionCount, isAuto);
    }


    /**
     * 统计更新
     *
     * @param cityCode
     * @param normalCount
     * @param exceptionCount
     * @param isAuto
     * @return
     */
    private int statisticsInsertOrUpdate(String cityCode, Long normalCount, Long exceptionCount, String isAuto) {
        int statistics = 0;
        if (BaseConstantCode.INSPECT_STATUS_AUTO.equalsIgnoreCase(isAuto)) {
            // 统计更新
            InspectStatistics inspectStatistics = new InspectStatistics();
            inspectStatistics.setCityCode(cityCode);
            String dateYm = new SimpleDateFormat(ymFormatStr).format(new Date());
            String dateD = new SimpleDateFormat("dd").format(new Date());
            inspectStatistics.setDateYm(dateYm);
            inspectStatistics.setDateD(dateD);
            // 判断插入还是更新
            InspectStatistics inspectStatisticsQuery = inspectStatisticsMapper.selectOne(inspectStatistics);
            inspectStatistics.setNormalCount(normalCount);
            inspectStatistics.setExceptionCount(exceptionCount);
            if (inspectStatisticsQuery != null) {
                inspectStatistics.setUpdateBy(userJenkins);
                inspectStatistics.setUpdateTime(new Date());
                Example example = new Example(InspectStatistics.class);
                example.createCriteria().andEqualTo(sqlCityCode, cityCode)
                        .andEqualTo("dateYm", dateYm)
                        .andEqualTo("dateD", dateD);

                statistics = inspectStatisticsMapper.updateByExampleSelective(inspectStatistics, example);
            } else {
                inspectStatistics.setId(idGenerator.nextId());
                inspectStatistics.setCityName(BaseConstants.getConstantsCodeMap().get(cityCode));
                inspectStatistics.setCreateBy(userJenkins);
                inspectStatistics.setCreateTime(new Date());
                statistics = inspectStatisticsMapper.insert(inspectStatistics);
            }
        }
        return statistics;
    }

    /**
     * 根据app数据启动Jenkins相关巡检
     *
     * @param inspectAreaAppList
     */
    private void jenkinsHealthJob(List<InspectAreaApp> inspectAreaAppList, String isAuto) {

        // 将所有app以区域分割点划分
        Map<String, List<InspectAreaApp>> map = new HashMap();
        for (InspectAreaApp inspectAreaApp : inspectAreaAppList) {
            if (map.get(inspectAreaApp.getCityCode()) == null) {
                List<InspectAreaApp> inspectAreaAppList1 = new ArrayList<>();
                inspectAreaAppList1.add(inspectAreaApp);
                map.put(inspectAreaApp.getCityCode(), inspectAreaAppList1);
            } else {
                List<InspectAreaApp> inspectAreaAppList2 = map.get(inspectAreaApp.getCityCode());
                inspectAreaAppList2.add(inspectAreaApp);
            }
        }

        // 保存调用url
        Map<Long, Map<String, String>> mapJenkins = new HashMap<>();
        // 根据区域调用job
        for (Map.Entry<String, List<InspectAreaApp>> entry : map.entrySet()) {
            Long batchNum = idGenerator.nextId();
            // 获取区域
            String inspectArea = entry.getKey();
            // 组装参数，第一个参数name=json，value={}
            JSONObject jsonObjectParam1 = new JSONObject();
            jsonObjectParam1.put("name", "json");
            StringBuilder jsonSB = new StringBuilder("[");
            List<InspectAreaApp> inspectAreaAppList3 = entry.getValue();
            for (InspectAreaApp inspectAreaApp : inspectAreaAppList3) {
                AppInfo appInfo = appInfoMapper.selectByPrimaryKey(inspectAreaApp.getAppId());
                String executeName = "";
                try {
                    executeName = appInfo.getBuildUrl().substring(1);
                    executeName = executeName.substring(0, executeName.indexOf('/'));
                } catch (Exception e) {
                    Assert.isTrue(false, inspectAreaApp.getCityName() + " " + inspectAreaApp.getAppName() + "获取巡查信息错误");
                    logger.error("at inspection, jenkins excuteName get error\nerror url {}:\n", appInfo.getBuildUrl(), e);
                }

                String inspectUrl = inspectAreaApp.getUrl();
                String[] inspectUrls = inspectUrl.split(",");
                // 巡查启动前，插入巡查历史
                insertHistory(inspectAreaApp, appInfo, isAuto, batchNum);
                JSONObject jsonObjectApp = new JSONObject();
                jsonObjectApp.put("app", executeName);
                jsonObjectApp.put("hcurl", inspectUrls);
                if (jsonSB.length() > 1) {
                    jsonSB.append(",");
                }
                jsonSB.append(jsonObjectApp.toString());
            }
            jsonSB.append("]");
            jsonObjectParam1.put(valueStr, jsonSB.toString());
            // 组装参数，第二个参数name=inspectCallBackMethod，value={}，回调函数
            JSONObject jsonObjectParam2 = new JSONObject();
            jsonObjectParam2.put("name", "inspectCallBackMethod");
            jsonObjectParam2.put(valueStr, jenkinsInfo.getCallBackHost() + jenkinsInfo.getInspectCallBackMethod());
            // 组装参数，第三个参数name=batchNum，value={}，批次码
            JSONObject jsonObjectParam3 = new JSONObject();
            jsonObjectParam3.put("name", batchNumStr);
            jsonObjectParam3.put(valueStr, String.valueOf(batchNum));

            // 组装参数，第四个参数name=env，运行环境dev， test, prod
            JSONObject jsonObjectParam4 = new JSONObject();
            jsonObjectParam4.put("name", "env");
            jsonObjectParam4.put(valueStr, System.getProperty("spring.profiles.active"));

            // 参数数组
            JSONArray jsonArrayParam = new JSONArray();
            jsonArrayParam.add(jsonObjectParam1);
            jsonArrayParam.add(jsonObjectParam2);
            jsonArrayParam.add(jsonObjectParam3);
            jsonArrayParam.add(jsonObjectParam4);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("parameter", jsonArrayParam.toArray());
            String params = "json=" + jsonObject.toString();

            // Jenkins巡检job启动 url拼接
            String inspectCallJob = jenkinsInfo.getInspectCallJob();
            inspectCallJob = MessageFormat.format(inspectCallJob, inspectArea);
            String remoteUrl = jenkinsInfo.getHost() + inspectCallJob + "?token=" + jenkinsInfo.getToken();

            // jenkins调用，urlencoded方式
            jenkinsCall(remoteUrl, params);
            // 保存调用Jenkins数据
            Map<String, String> mapInfo = new HashMap<>();
            mapInfo.put(remoteUrl, params);
            mapJenkins.put(batchNum, mapInfo);
        }

        // 开启数据获取保证线程
        watchJenkins(mapJenkins, isAuto);
    }


    /**
     * 启数据获取保证线程
     *
     * @param map
     */
    private void watchJenkins(Map<Long, Map<String, String>> map, String isAuto) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                // 巡查次数，调用任务之前已经执行一次
                int count = 1;
                // 最大巡查次数
                int countMax = Integer.parseInt(jenkinsInfo.getInspectCallMaxRepeatCount());
                // 两次巡查之间等待时间
                Long sleepTime = Long.parseLong(jenkinsInfo.getInspectCallWaitTime()) * 1000L;
                while (true) {
                    // 巡查次数达到最大值时，则不再巡查
                    if (count >= countMax || map.size() == 0) {
                        if (count >= countMax) {
                            // 非正常结束，更新为异常结束
                            for (Map.Entry<Long, Map<String, String>> entry : map.entrySet()) {
                                Long batchNum = entry.getKey();
                                Example example = new Example(InspectHistory.class);
                                example.createCriteria().andEqualTo(batchNumStr, batchNum);
                                List<InspectHistory> inspectHistoryList = inspectHistoryMapper.selectByExample(example);
                                if (!inspectHistoryList.isEmpty()) {
                                    statisticsInsertOrUpdate(inspectHistoryList.get(0).getCityCode(), 0L, (long) inspectHistoryList.size(), isAuto);
                                }
                                InspectHistory inspectHistory = new InspectHistory();
                                inspectHistory.setStatus(BaseConstantCode.INSPECT_STATUS_EXCEPTION);
                                inspectHistory.setUpdateBy(userJenkins);
                                inspectHistory.setUpdateTime(new Date());
                                inspectHistoryMapper.updateByExampleSelective(inspectHistory, example);
                            }
                        }
                        break;
                    }
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        logger.error("Inspect watchJenkins sleep Exception : {}", ie);
                    }
                    // 存放下次需要重发的数据
                    Map<Long, Map<String, String>> mapNew = new HashMap<>();
                    for (Map.Entry<Long, Map<String, String>> mapEntry : map.entrySet()) {
                        // 查询巡查历史状态
                        Example example = new Example(InspectHistory.class);
                        example.createCriteria().andEqualTo(batchNumStr, mapEntry.getKey())
                                .andEqualTo(statusStr, BaseConstantCode.INSPECT_STATUS_DOING);
                        int countDoing = inspectHistoryMapper.selectCountByExample(example);
                        // 存在未获得结果的巡查，则再次发出巡查请求
                        if (countDoing > 0) {
                            for (Map.Entry<String, String> entry : mapEntry.getValue().entrySet()) {
                                // jenkins调用，urlencoded方式
                                String remoteUrl = entry.getKey();
                                String params = entry.getValue();
                                jenkinsCall(remoteUrl, params);
                            }
                            mapNew.put(mapEntry.getKey(), mapEntry.getValue());
                        }
                    }
                    map.clear();
                    map.putAll(mapNew);
                    // 巡查次数
                    count++;
                }
            }
        };
        // 启动线程
        thread.start();
    }

    /**
     * jenkins调用，urlencoded方式
     *
     * @param remoteUrl
     * @param params
     */
    private void jenkinsCall(String remoteUrl, String params) {
        // http请求header，urlencoded方式
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // Jenkins巡检job启动
        HttpEntity requestEntity = new HttpEntity<>(params, headers);
        try {
            logger.info("jenkinsHealthJob call url:{}\n\t\t\t\tparameter:{}", remoteUrl, params);
            ResponseEntity<String> responseEntity = restTemplate.exchange(remoteUrl,
                    HttpMethod.POST, requestEntity, String.class);
            String response = GsonUtils.getInstance().toJson(responseEntity);
            logger.info("jenkinsHealthJob return result:{}", response);
        } catch (Exception e) {
            logger.error("jenkinsHealthJob call failed\n\t\t\t\terrorMessage:", e);
        }
    }

    /**
     * 巡查启动前，插入巡查历史
     *
     * @param inspectAreaApp
     * @param appInfo
     * @param isAuto
     * @param batchNum
     */
    private void insertHistory(InspectAreaApp inspectAreaApp, AppInfo appInfo, String isAuto, Long batchNum) {
        String inspectUrl = inspectAreaApp.getUrl();
        String[] inspectUrls = inspectUrl.split(",");
        for (String inspectUrlSingle : inspectUrls) {
            // 保存数据
            InspectHistory inspectHistory = new InspectHistory();
            inspectHistory.setId(idGenerator.nextId());
            inspectHistory.setCityCode(inspectAreaApp.getCityCode());
            inspectHistory.setCityName(inspectAreaApp.getCityName());
            inspectHistory.setProjectName(appInfo.getProjectName());
            inspectHistory.setAppName(appInfo.getAppName());
            inspectHistory.setType(inspectAreaApp.getTypeCode());
            inspectHistory.setDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
            inspectHistory.setStatus(BaseConstantCode.INSPECT_STATUS_DOING);
            inspectHistory.setIsAuto(isAuto);
            inspectHistory.setBatchNum(batchNum);
            inspectHistory.setDeployUrl(inspectUrlSingle);
            inspectHistory.setCreateBy("123");
            inspectHistory.setCreateTime(new Date());
            inspectHistoryMapper.insert(inspectHistory);
        }
    }

    /**
     * 区域城市配置新增
     *
     * @param inspectAreaAppVo
     * @return
     */
    @Override
    public int areaAppAdd(InspectAreaAppVo inspectAreaAppVo) {
        int insertCount = 0;
        if (inspectAreaAppVo != null) {
            // 判断是否添加重复，以城市code和appId联合判断
            areaAppRepeat(inspectAreaAppVo);
            InspectAreaApp inspectAreaApp = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(inspectAreaAppVo),
                    new TypeToken<InspectAreaApp>() {
                    }.getType());
            inspectAreaApp.setId(idGenerator.nextId());
            inspectAreaApp.setTypeName(BaseConstants.getConstantsCodeMap().get(inspectAreaApp.getTypeCode()));
            inspectAreaApp.setCityName(BaseConstants.getConstantsCodeMap().get(inspectAreaApp.getCityCode()));
            inspectAreaApp.setCreateBy("123");
            inspectAreaApp.setCreateTime(new Date());
            insertCount = inspectAreaAppMapper.insert(inspectAreaApp);
        }
        return insertCount;
    }

    /**
     * 区域城市配置编辑
     *
     * @param inspectAreaAppVo
     * @return int
     */
    @Override
    public int areaAppEdit(InspectAreaAppVo inspectAreaAppVo) {
        int count = 0;
        if (inspectAreaAppVo != null) {
            // 校验名称和城市的组合是否重复
            areaAppRepeat(inspectAreaAppVo);
            InspectAreaApp inspectAreaApp = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(inspectAreaAppVo),
                    new TypeToken<InspectAreaApp>() {
                    }.getType());
            inspectAreaApp.setTypeName(BaseConstants.getConstantsCodeMap().get(inspectAreaApp.getTypeCode()));
            inspectAreaApp.setCityName(BaseConstants.getConstantsCodeMap().get(inspectAreaApp.getCityCode()));
            inspectAreaApp.setUpdateBy("123");
            inspectAreaApp.setUpdateTime(new Date());
            Example example = new Example(InspectAreaApp.class);
            example.createCriteria().andEqualTo("id", inspectAreaAppVo.getId());
            count = inspectAreaAppMapper.updateByExampleSelective(inspectAreaApp, example);
        }
        return count;
    }

    /**
     * 判断是否添加重复，以城市code和appId联合判断
     *
     * @param inspectAreaAppVo
     */
    private void areaAppRepeat(InspectAreaAppVo inspectAreaAppVo) {
        if (inspectAreaAppVo.getAppId() == null) {
            Assert.isTrue(false, "请选择应用名");
        }
        if (StringUtils.isBlank(inspectAreaAppVo.getCityCode())) {
            Assert.isTrue(false, "请选择城市");
        }
        // 判断是否添加重复，以城市code和appId联合判断
        Example example = new Example(InspectAreaApp.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("appId", inspectAreaAppVo.getAppId())
                .andEqualTo(sqlCityCode, inspectAreaAppVo.getCityCode());
        if (inspectAreaAppVo.getId() != null) {
            criteria.andNotEqualTo("id", inspectAreaAppVo.getId());
        }
        if (inspectAreaAppMapper.selectCountByExample(example) > 0) {
            Assert.isTrue(false, "应用名和城市组合重复");
        }
    }

    /**
     * 区域城市配置删除
     *
     * @param inspectAreaAppVo
     * @return int
     */
    @Override
    public int areaAppDelete(InspectAreaAppVo inspectAreaAppVo) {
        int count = 0;
        if (inspectAreaAppVo != null) {
            count = inspectAreaAppMapper.deleteByPrimaryKey(inspectAreaAppVo.getId());
        }
        return count;
    }

    /**
     * 区域城市配置翻页查询
     *
     * @param inspectRequest
     * @return
     */
    @Override
    public IPage<InspectAreaAppVo> areaAppListByPage(InspectRequest inspectRequest) {
        // 创建翻页对象
        Page<InspectAreaApp> page = PageHelper.startPage(inspectRequest.getPageNum(), inspectRequest.getPageSize());
        Example example = new Example(InspectAreaApp.class);
        example.setOrderByClause("CREATE_TIME DESC");
        Example.Criteria criteria = example.createCriteria();
        if (inspectRequest.getAppId() != null) {
            criteria.andEqualTo("appId", inspectRequest.getAppId());
        }
        if (StringUtils.isNotBlank(inspectRequest.getCityCode())) {
            criteria.andEqualTo(sqlCityCode, inspectRequest.getCityCode());
        }
        inspectAreaAppMapper.selectByExample(example);
        IPage<InspectAreaAppVo> iPage = ConvertUtil.pageToIpage(page, new IPage<InspectAreaAppVo>());
        List<InspectAreaAppVo> inspectAreaAppVoList = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(page), new TypeToken<List<InspectAreaAppVo>>() {
        }.getType());
        iPage.setResult(inspectAreaAppVoList);
        return iPage;
    }

    /**
     * 区域城市配置单个查询
     *
     * @param inspectAreaAppVo
     * @return InspectAreaAppVo
     */
    @Override
    public InspectAreaAppVo areaAppGetOne(InspectAreaAppVo inspectAreaAppVo) {
        InspectAreaAppVo inspectAreaAppVo1 = new InspectAreaAppVo();
        if (inspectAreaAppVo != null) {
            InspectAreaApp inspectAreaApp = inspectAreaAppMapper.selectByPrimaryKey(inspectAreaAppVo.getId());
            inspectAreaAppVo1 = GsonUtils.getInstance().fromJson(GsonUtils.getInstance().toJson(inspectAreaApp),
                    new TypeToken<InspectAreaAppVo>() {
                    }.getType());
        }
        return inspectAreaAppVo1;
    }

    /**
     * 获得所有有效的app
     *
     * @return
     */
    @Override
    public List<SelectedVo> getAppList(AppInfoRequest request) {
        // 组装查询条件
        Example example = new Example(AppInfo.class);
        example.setOrderByClause("CREATE_TIME DESC");
        if (StringUtils.isNotBlank(request.getAppName())) {
            example.createCriteria().andLike("appName", "%" + request.getAppName() + "%");
        }
        // 查询并设置数据
        List<AppInfo> appInfoList = appInfoMapper.selectByExample(example);
        List<SelectedVo> selectedVoList = new ArrayList<>();

        for (AppInfo appInfo : appInfoList) {
            SelectedVo selectedVo = new SelectedVo();
            selectedVo.setCode(String.valueOf(appInfo.getId()));
            selectedVo.setName(appInfo.getAppName());
            selectedVoList.add(selectedVo);
        }
        return selectedVoList;
    }

}
